﻿namespace Summoner
{
    using UnityEngine;
    using System;
    using System.Collections;
    using Object = UnityEngine.Object;
    public class LoadFunction : MonoBehaviour
    {
        private static LoadFunction _instance = null;

        #region Init
        private IEnumerator InitIEnum(Action OnManifestLoaded)
        {
            AssetBundleLoadManifestOperation request = AssetBundleManager.instance.Initialize("StreamingAssets");
            if (request != null)
            {
                yield return StartCoroutine(request);
                if (OnManifestLoaded != null)
                {
                    OnManifestLoaded();
                }
            }
        }

        public void Init(Action OnManifestLoaded)
        {
            StartCoroutine(this.InitIEnum(OnManifestLoaded));
        }
        #endregion

        #region Load config
        IEnumerator ConfigIEnum(string url, Action<string> callback = null)
        {
            WWW www = new WWW(url);
            while(!www.isDone)
            {
                yield return null;
            }
            if(!string.IsNullOrEmpty(www.error))
            {
                Debug.LogError(www.error);
            }
            else
            {
                if (callback != null) { callback(www.text); }
            }
            www.Dispose();
        }

        public void LoadConfig(string url, Action<string> callback = null)
        {
            StartCoroutine(this.ConfigIEnum(url, callback));
        }
        #endregion

        #region Load bundle Async
        IEnumerator AssetBundleIEnum(LoadMission info, Action<object> callback = null, object parameter = null)
        {
            AssetBundleLoadAssetOperation request = AssetBundleManager.instance.LoadAssetAsync(info.assetname.ToLower() + ".unity3d", info.assetname, typeof(Object));
            if (request == null) { yield break; }
            yield return StartCoroutine(request);
            if (callback != null)
            {
                Object obj = request.GetAsset<Object>();
                if (parameter == null)
                {
                    if (info.type == "UnityEngine.GameObject")
                    {
                        callback(Instantiate(obj));
                    }
                    else
                    {
                        callback(obj);
                    }
                }
                else
                {
                    if (info.type == "UnityEngine.GameObject")
                    {
                        callback(new LoadParam() { obj = Instantiate(obj), parameter = parameter });
                    }
                    else
                    {
                        callback(new LoadParam() { obj = obj, parameter = parameter });
                    }
                }
            }
        }

        public void LoadBundleAsync(LoadMission info, Action<object> callback = null, object parameter = null)
        {
            StartCoroutine((this.AssetBundleIEnum(info, callback, parameter)));
        }
        #endregion

        #region Load bundle with type
        IEnumerator BundleWithTypeIEnum<T>(AssetInfo info = null, Action<T> callback = null) where T : Object
        {
            AssetBundleLoadAssetOperation request = AssetBundleManager.instance.LoadAssetAsync(info.assetName.ToLower() + ".unity3d", info.assetName, typeof(Object));
            if (request == null) { yield break; }
            yield return StartCoroutine(request);
            if (callback != null)
            {
                Object obj = request.GetAsset<Object>();
                if (info.type == "UnityEngine.GameObject")
                {
                    callback(Instantiate(obj) as T);
                }
                else
                {
                    callback(obj as T);
                }
            }
        }

        public void LoadBundleAsyncWithType<T>(Action<T> callback = null, AssetInfo info = null) where T : Object
        {
            StartCoroutine((this.BundleWithTypeIEnum<T>(info, callback)));
        }
        #endregion

        #region Load bundle Sync
        public AssetBundle LoadBundleSync(string assetName)
        {
            return AssetBundleManager.instance.LoadAssetBundleSync(assetName.ToLower() + ".unity3d");
        }
        #endregion

        #region Load Image file
        IEnumerator ImageEnum(string url, Action<Texture2D> callback)
        {
            WWW www = new WWW(url);
            while (!www.isDone)
            {
                yield return null;
            }
            if (!string.IsNullOrEmpty(www.error))
            {
                Debug.LogError(www.error);
            }
            else
            {
                Texture2D tex = new Texture2D(4, 4, TextureFormat.RGBA32, false);
                www.LoadImageIntoTexture(tex);
                if (callback != null) { callback(tex); }
            }
            www.Dispose();
        }

        public void LoadImageAsync(string url, Action<Texture2D> callback)
        {
            StartCoroutine(this.ImageEnum(url, callback));
        }
        #endregion

        /// <summary>
        /// Unload an AssetBundle
        /// </summary>
        /// <param name="url"></param>
        /// <param name="version"></param>
        /// <param name="allObjects"></param>
        public void UnloadAsync(string uniqueName)
        {
            AssetBundleManager.instance.UnloadAssetBundleAsync(uniqueName.ToLower() + ".unity3d");
        }

        public void UnloadSync(string uniqueName)
        {
            AssetBundleManager.instance.UnloadAssetBundleSync(uniqueName.ToLower() + ".unity3d");
        }

        public static LoadFunction instance
        {
            get
            {
                if (_instance == null) { _instance = FindObjectOfType<LoadFunction>(); }
                if (_instance == null) { _instance = new GameObject("LoadFunction").AddComponent<LoadFunction>(); }
                return _instance;
            }
        }
    }
}